package br.com.trabalho4.model.shape;

import java.awt.Graphics;

public class Line implements Shape {
	
	private Point begin;
	private Point end;
	
	private int zoom;
	
	public Line(Point begin, Point end, int zoom) {
		this.begin = begin;
		this.end = end;
		this.zoom = zoom;
	}
	
	public Line(Point begin, Point end) {
		this.begin = begin;
		this.end = end;
		this.zoom = 1;
	}

	@Override
	public void draw(Graphics g) {
		Graphics gg = g.create();
		
//		{
//			double x = begin.getX();
//            double y = begin.getY();
//            double deltaX, deltaY,s1,s2,tmp = 0;
//            double e = 0;
//            deltaX = Math.abs(end.getX() - begin.getX());
//            deltaY = Math.abs(end.getY() - begin.getY());
//            s1 = Math.signum(end.getX() - begin.getX());
//            s2 = Math.signum(end.getY() - begin.getY());
//            boolean trocaInclinacao = false;
//            
//            if (s1 < 0)
//                    x -= 1;
//            if (s2 < 0)
//                    y -= 1;
//            
//            if(deltaY > deltaX){
//                    tmp = deltaX;
//                    deltaX=deltaY;
//                    deltaY=tmp;
//                    trocaInclinacao=true;
//            }
//            
//                    
//            e = 2* deltaY - deltaX;
//
//            for (int i = 0; i <= (int) Math.round(deltaX); i++) {
//                    
//            	Point p = new Point((int) Math.round(x), (int) Math.round(y), zoom);
//            	p.draw(gg);
//                    
//                    while (e >= 0) {
//
//                            if(trocaInclinacao)
//                                    x = x + s1;
//                            else
//                                    y = y + s2;
//                            
//                            e = e - 2*deltaX;
//                            
//                    }
//                    
//                    if(trocaInclinacao)
//                            y = y + s2;
//                    else
//                            x = x + s1;
//                    
//                    e = e + 2*deltaY;
//            }
//		}
		
//		{
//			int slope;
//			int dx, dy, incE, incNE, d, x, y;
//			
//			if (begin.getX() > end.getX()) {
//				new Line(end, begin).draw(gg);
//				return;
//			}
//			
//			dx = end.getX() - begin.getX();
//			dy = end.getY() - begin.getY();
//			
//			if (dy < 0) {
//				slope = -1;
//				dy = -dy;
//			} else {
//				slope = 1;
//			}
//			
//			incE = 2*dy;
//			incNE = 2*dy-2*dx;
//			d = 2*dy-dx;
//			y = begin.getY();
//			
//			for (x = begin.getX(); x <= end.getX(); x++) {
//				Point p = new Point(x, y, zoom);
//				p.setZoom(zoom);
//				p.draw(gg);
//				
//				if (d <= 0) {
//					d += incNE;
//				} else {
//					d += incNE;
//					y += slope;
//				}
//			}
//		}
		
//		{
//			int DDx, Dx = end.getX() - begin.getX();
//			int DDy, Dy = end.getY() - begin.getY();
//			
//			DDx = Dx<<1;
//			DDy = Dy<<1;
//			
//			int e = -Dx;
//			int x, y = end.getY();
//			
//			int style[] = {1,1,0,0,1,1,0,0};
//			int k = 1;
//			
//			//begin.draw(gg);
//			
//			for (x=begin.getX(); x<=end.getX(); x++) {
//				e += DDy;
//				
//				if (e >= 0) {
//					y++;
//					e -= DDx;
//				}
//				
//	//			if (style[(++k)%8] == 1) {
//				Point p = new Point(x, y, zoom);
//				p.setZoom(zoom);
//				p.draw(gg);
//	//			}
//			}
//		}
		
		{
			int style[] = {1,1,0,0,1,1,0,0};
			int k = 1;
			
			int x, y, erro, deltaX, deltaY;
			erro = 0;
			x = begin.getX();
			y = begin.getY();
			deltaX = end.getX() - begin.getX();
			deltaY = end.getY() - begin.getY();
	 
			if((Math.abs(deltaY)>=Math.abs(deltaX) && begin.getY()>end.getY()) || (Math.abs(deltaY)<Math.abs(deltaX) && deltaY<0)){
	 
				x = end.getX();
				y = end.getY();
				deltaX = begin.getX()-end.getX();
				deltaY = begin.getY()-end.getY();
			}
			
			begin.setZoom(zoom);
			begin.draw(gg);
			
			if(deltaX>=0){
				if(Math.abs(deltaX)>=Math.abs(deltaY)){
					for(int i=1;i<Math.abs(deltaX);i++){
						if(erro<0){
							x++;
							if (style[(++k)%8] == 1) {
								new Point(x,y,zoom).draw(gg);
							}
							erro += deltaY;
						}else{
							x++;
							y++;
							if (style[(++k)%8] == 1) {
								new Point(x,y,zoom).draw(gg);
							}
							erro += deltaY - deltaX;
						}
					}
				}else{
					for(int i=1;i<Math.abs(deltaY);i++){
						if(erro<0){
							x++;
							y++;
							if (style[(++k)%8] == 1) {
								new Point(x,y,zoom).draw(gg);
							}
							erro += deltaY - deltaX;						
						}else{
							y++;
							if (style[(++k)%8] == 1) {
								new Point(x,y,zoom).draw(gg);
							}
							erro -= deltaX;
						}
					}
				}
			}else{ // deltaX<0
				if(Math.abs(deltaX)>=Math.abs(deltaY)){
					for(int i=1;i<Math.abs(deltaX);i++){
						if(erro<0){
							x--;
							if (style[(++k)%8] == 1) {
								new Point(x,y,zoom).draw(gg);
							}
							erro += deltaY;
						}else{
							x--;
							y++;
							if (style[(++k)%8] == 1) {
								new Point(x,y,zoom).draw(gg);
							}
							erro += deltaY + deltaX;
						}
					}
				}else{
					for(int i=1;i<Math.abs(deltaY);i++){
						if(erro<0){
							x--;
							y++;
							if (style[(++k)%8] == 1) {
								new Point(x,y,zoom).draw(gg);
							}
							erro += deltaY + deltaX;						
						}else{
							y++;
							if (style[(++k)%8] == 1) {
								new Point(x,y,zoom).draw(gg);
							}
							erro += deltaX;
						}
					}
				}
			}
			
			end.setZoom(zoom);
			end.draw(gg);
		}
		
		gg.dispose();
	}
	
	public void draw(Graphics g, Point p) {
		Graphics gg = g.create();
		{
			int x, y, erro, deltaX, deltaY;
			erro = 0;
			x = begin.getX();
			y = begin.getY();
			deltaX = end.getX() - begin.getX();
			deltaY = end.getY() - begin.getY();
	 
			if((Math.abs(deltaY)>=Math.abs(deltaX) && begin.getY()>end.getY()) || (Math.abs(deltaY)<Math.abs(deltaX) && deltaY<0)){
	 
				x = end.getX();
				y = end.getY();
				deltaX = begin.getX()-end.getX();
				deltaY = begin.getY()-end.getY();
			}
			
			begin.setZoom(zoom);
			begin.draw(gg);
			
			if(deltaX>=0){
				if(Math.abs(deltaX)>=Math.abs(deltaY)){
					for(int i=1;i<Math.abs(deltaX);i++){
						if(erro<0){
							x++;
							new Line(new Point(x,y,zoom), p, zoom).draw(gg);
							erro += deltaY;
						}else{
							x++;
							y++;
							new Line(new Point(x,y,zoom), p, zoom).draw(gg);
							erro += deltaY - deltaX;
						}
					}
				}else{
					for(int i=1;i<Math.abs(deltaY);i++){
						if(erro<0){
							x++;
							y++;
							new Line(new Point(x,y,zoom), p, zoom).draw(gg);
							erro += deltaY - deltaX;						
						}else{
							y++;
							new Line(new Point(x,y,zoom), p, zoom).draw(gg);
							erro -= deltaX;
						}
					}
				}
			}else{ // deltaX<0
				if(Math.abs(deltaX)>=Math.abs(deltaY)){
					for(int i=1;i<Math.abs(deltaX);i++){
						if(erro<0){
							x--;
							new Line(new Point(x,y,zoom), p, zoom).draw(gg);
							erro += deltaY;
						}else{
							x--;
							y++;
							new Line(new Point(x,y,zoom), p, zoom).draw(gg);
							erro += deltaY + deltaX;
						}
					}
				}else{
					for(int i=1;i<Math.abs(deltaY);i++){
						if(erro<0){
							x--;
							y++;
							new Line(new Point(x,y,zoom), p, zoom).draw(gg);
							erro += deltaY + deltaX;						
						}else{
							y++;
							new Line(new Point(x,y,zoom), p, zoom).draw(gg);
							erro += deltaX;
						}
					}
				}
			}
			end.setZoom(zoom);
			end.draw(gg);
		}
		
		gg.dispose();
	}
	
	@Override
	public void setZoom(int zoom) {
		this.zoom = zoom;
	}
	
	public Point getBegin() {
		return begin;
	}

	public void setBegin(Point begin) {
		this.begin = begin;
	}

	public Point getEnd() {
		return end;
	}

	public void setEnd(Point end) {
		this.end = end;
	}

}
